/**
 * @copyright 2017 Indie Semiconductor.
 *
 * This file is proprietary to Indie Semiconductor.
 * All rights reserved. Reproduction or distribution, in whole
 * or in part, is forbidden except by express written permission
 * of Indie Semiconductor.
 *
 * @file gpio_device.c
 */
#include "gpio_device.h"


//GPIO1           ->GAP4
//GPIO2           ->GAP3
//GPIO3           ->GAP1
//GPIO4(RXD)      ->GAP0
//GPIO5(TXD)      ->GAP2
//  GPIO_PORT_1 = 4,
//  GPIO_PORT_2 = 3,
//  GPIO_PORT_3 = 1,
//  GPIO_PORT_4 = 0,
//  GPIO_PORT_5 = 2,

gpio_cb_func_t gpioCallback[5]= {NULL, NULL,NULL,NULL,NULL};

void GPIO_Handler( void )
{

    if(GPIOA_SFRS->GPAP4.ACTDET4 == 1){//GPIO1
        GPIOA_SFRS->GPAP4.CLR4 = 1;
        if (gpioCallback[GPIO_PORT_1] !=NULL){
            gpioCallback[GPIO_PORT_1]();
        }
    }

    if(GPIOA_SFRS->GPAP03.port[GPIO_PORT_2].ACTDET == 1){//GPIO2
        GPIOA_SFRS->GPAP03.port[GPIO_PORT_2].CLR = 1; 
        if (gpioCallback[GPIO_PORT_2] !=NULL){
            gpioCallback[GPIO_PORT_2]();
        }
    }
    
    if(GPIOA_SFRS->GPAP03.port[GPIO_PORT_3].ACTDET == 1){//GPIO3
        GPIOA_SFRS->GPAP03.port[GPIO_PORT_3].CLR = 1; 
        if (gpioCallback[GPIO_PORT_3] !=NULL){
            gpioCallback[GPIO_PORT_3]();
        }
    }
    
    if(GPIOA_SFRS->GPAP03.port[GPIO_PORT_4].ACTDET == 1){//GPIO4
        GPIOA_SFRS->GPAP03.port[GPIO_PORT_4].CLR = 1; 
        if (gpioCallback[GPIO_PORT_4] !=NULL){
            gpioCallback[GPIO_PORT_4]();
        }
    }
    
    if(GPIOA_SFRS->GPAP03.port[GPIO_PORT_5].ACTDET == 1){//GPIO5
        GPIOA_SFRS->GPAP03.port[GPIO_PORT_5].CLR = 1; 
        if (gpioCallback[GPIO_PORT_5] !=NULL){
            gpioCallback[GPIO_PORT_5]();
        }
    }

}


//GPIO1           ->GAP4
//GPIO2           ->GAP3
//GPIO3           ->GAP1
//GPIO4(RXD)      ->GAP0
//GPIO5(TXD)      ->GAP2
//  GPIO_PORT_1 = 4,
//  GPIO_PORT_2 = 3,
//  GPIO_PORT_3 = 1,
//  GPIO_PORT_4 = 0,
//  GPIO_PORT_5 = 2,
void GPIO_Init(GpioPort_t port, GpioMuxMode_t muxMode, GpioDir_t stateMode,GpioPullMode_t pullMode)
{
    
    if (port == GPIO_PORT_1){
        GPIOA_SFRS->GPAP4.DIR4 = stateMode;
    }else{
        GPIOA_SFRS->GPAP03.port[port].DIR = stateMode;
    }
    
    if(muxMode == GPIO_MUX_GPIO){
        if (port != GPIO_PORT_1){
            IOCTRLA_SFRS->GPIO[port].HWMODE = 0;
            if (pullMode == GPIO_PULL_MODE_PULLUP){
                IOCTRLA_SFRS->GPIO[port].PUENA = 1; //0x1: Enable 100K Ohm Pull Up    0x0: Disable 100K Ohm Pull Up
                IOCTRLA_SFRS->GPIO[port].PDENA = 0; //0x0: Disable 100K Ohm Pull Down 0x1: Enable 100K Ohm Pull Down
            }else if (pullMode == GPIO_PULL_MODE_PULLDOWN){
                IOCTRLA_SFRS->GPIO[port].PUENA = 0; //0x1: Enable 100K Ohm Pull Up    0x1: Disable 100K Ohm Pull Up
                IOCTRLA_SFRS->GPIO[port].PDENA = 1; //0x0: Disable 100K Ohm Pull Down 0x1: Enable 100K Ohm Pull Down
            }else{
                IOCTRLA_SFRS->GPIO[port].PUENA = 0; //0x1: Enable 100K Ohm Pull Up    0x1: Disable 100K Ohm Pull Up
                IOCTRLA_SFRS->GPIO[port].PDENA = 0; //0x0: Disable 100K Ohm Pull Down 0x1: Enable 100K Ohm Pull Down
            }
        }else{
            if (pullMode == GPIO_PULL_MODE_PULLUP){
                IOCTRLA_SFRS->GPAP4.PUENA4 = 1; //0x1: Enable 100K Ohm Pull Up    0x0: Disable 100K Ohm Pull Up
                IOCTRLA_SFRS->GPAP4.PDENA4 = 0; //0x0: Disable 100K Ohm Pull Down 0x1: Enable 100K Ohm Pull Down
            }else if (pullMode == GPIO_PULL_MODE_PULLDOWN){
                IOCTRLA_SFRS->GPAP4.PUENA4 = 0; //0x1: Enable 100K Ohm Pull Up    0x1: Disable 100K Ohm Pull Up
                IOCTRLA_SFRS->GPAP4.PDENA4 = 1; //0x0: Disable 100K Ohm Pull Down 0x1: Enable 100K Ohm Pull Down
            }else{
                IOCTRLA_SFRS->GPAP4.PUENA4 = 0; //0x1: Enable 100K Ohm Pull Up    0x1: Disable 100K Ohm Pull Up
                IOCTRLA_SFRS->GPAP4.PDENA4 = 0; //0x0: Disable 100K Ohm Pull Down 0x1: Enable 100K Ohm Pull Down
            }
        }
    }else if(muxMode == GPIO_MUX_UART){
    }
}

//GPIO1           ->GAP4
//GPIO2           ->GAP3
//GPIO3           ->GAP1
//GPIO4(RXD)      ->GAP0
//GPIO5(TXD)      ->GAP2
//  GPIO_PORT_1 = 4,
//  GPIO_PORT_2 = 3,
//  GPIO_PORT_3 = 1,
//  GPIO_PORT_4 = 0,
//  GPIO_PORT_5 = 2,
void GPIO_RegisterIRQ(GpioPort_t port, bool risingEdge, gpio_cb_func_t callback)
{
    if (port == GPIO_PORT_1){
        GPIOA_SFRS->GPAP4.RE4 = risingEdge;
        GPIOA_SFRS->GPAP4.FE4 = !risingEdge;
        GPIOA_SFRS->GPAP4.CLR4 = 1;
        GPIOA_SFRS->GPAP4.ACTDET4 = 1;
    }else{
        GPIOA_SFRS->GPAP03.port[port].RE     = risingEdge;
        GPIOA_SFRS->GPAP03.port[port].FE     = !risingEdge;
        GPIOA_SFRS->GPAP03.port[port].CLR    = 1;
        GPIOA_SFRS->GPAP03.port[port].ACTDET = 1;
    }
    gpioCallback[port] = callback;
    NVIC_EnableIRQ(GPIO_IRQn);
}


//GPIO1           ->GAP4
//GPIO2           ->GAP3
//GPIO3           ->GAP1
//GPIO4(RXD)      ->GAP0
//GPIO5(TXD)      ->GAP2
//  GPIO_PORT_1 = 4,
//  GPIO_PORT_2 = 3,
//  GPIO_PORT_3 = 1,
//  GPIO_PORT_4 = 0,
//  GPIO_PORT_5 = 2,

void GPIO_UnRegisterIRQ(GpioPort_t port)
{
    if (port == GPIO_PORT_1){
          GPIOA_SFRS->GPAP4.CLR4 = 1;
          GPIOA_SFRS->GPAP4.ACTDET4 = 0;
    }else{
        GPIOA_SFRS->GPAP03.port[port].CLR = 1;
        GPIOA_SFRS->GPAP03.port[port].ACTDET = 0;
    }
    gpioCallback[port] = NULL;
}

void GPIO_Set(GpioPort_t port, bool state)
{
    GPIOA_SFRS->GPADATA[(1 << port) << 2] = ((uint8_t)state << port);
}

bool GPIO_Read(GpioPort_t port)
{
    uint8_t data;
    data = GPIOA_SFRS->GPADATA[(1 << port) << 2];
    return (data != 0);
}
//portsMask <=0x1F
//value <= 0x1F 
void GPIO_SetPorts(uint8_t portsMask, uint8_t value)
{
    GPIOA_SFRS->GPADATA[portsMask << 2] = value;
}

//portsMask <=0x1F
//value <= 0x1F 
uint8_t GPIO_ReadPorts(uint8_t portsMask)
{
    uint8_t data;
    data = GPIOA_SFRS->GPADATA[portsMask << 2];
    return data;
}